package cn.itsource.service.impl;

import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import cn.itsource.constants.CacheConstants;
import cn.itsource.constants.ErrorCode;
import cn.itsource.constants.RConst;
import cn.itsource.exception.GlobalException;
import cn.itsource.pojo.domain.Login;
import cn.itsource.mapper.LoginMapper;
import cn.itsource.pojo.dto.RegisterDto;
import cn.itsource.pojo.ro.AppLoginRo;
import cn.itsource.pojo.ro.ManagerLoginRo;
import cn.itsource.pojo.vo.ManagerInfoVo;
import cn.itsource.pojo.vo.UserInfoVo;
import cn.itsource.result.JSONResult;
import cn.itsource.service.ILoginService;
import cn.itsource.service.WeChatService;
import cn.itsource.utils.AssertUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author zcj
 * @since 2024-07-06
 */
@Service
@Slf4j
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private LoginMapper loginMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;


    @Override
    public JSONResult appLogin(AppLoginRo login) {
        //分析  逻辑 做登录
        //已有  code   --->  openId
        RegisterDto weChatOpenId = weChatService.getWeChatOpenId(login.getCode());
        String openid = weChatOpenId.getOpenid();
        AssertUtil.isNotNull(openid,"获取openid失败,请检查");
        log.info("当前code:{}获取openId失败",login.getCode());
        //比较openId
        //既是用户又是司机
        Login one = super.getOne(new LambdaQueryWrapper<Login>().eq(Login::getOpenId, openid)
                .eq(Login::getType, login.getType()));
        if(one != null){
            getPermissionList(one);
            //返回token
            String tokenValue = StpUtil.getTokenValue();

            //封装返回app
            UserInfoVo userInfoVo = UserInfoVo.toUserInfoVo(one, tokenValue);
            return JSONResult.success(userInfoVo);
        }
        return JSONResult.error(ErrorCode.WE_CHAT_LOGIN_ERROR);
    }

    @Override
    public JSONResult managerLogin(ManagerLoginRo login) {
        //先确定有没有用户
        String username = login.getUsername();
        Long type = login.getType();
        Login one = super.getOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getUsername, username).eq(Login::getType, type));
        AssertUtil.isNotNull(one,"用户名或密码错误");

        //在确定密码对不对
        boolean matches = bCryptPasswordEncoder.matches(login.getPassword(), one.getPassword());
        AssertUtil.isTrue(matches,"用户名或密码错误");

        //当前账号是否禁用
        AssertUtil.isTrue(one.getEnabled(),"当前账号被禁用了");

        //封装返回 manager  后台管理端的
        List<String> permissionList = getPermissionList(one);
        String tokenValue = StpUtil.getTokenValue();
        one.setPassword("");//保存账号的安全
        ManagerInfoVo managerInfoVo = new ManagerInfoVo(tokenValue,permissionList,one);
        return JSONResult.success(managerInfoVo);
    }

    private List<String> getPermissionList(Login one) {
        //登录成功 这里的代码就将用户数据保存到token里面 jwt
        StpUtil.login(one.getId(),
                SaLoginConfig.setExtra("userinfo", one)
                        .setExtra("openId",one.getOpenId()));

        //去查询数据库 将权限保存到redis里面
        List<String> permissionList =
                loginMapper.selectPermissionByLoginId(Long.valueOf(one.getId().toString()));
        System.err.println(String.join(",",permissionList));
        //存入redis
        String key = CacheConstants.CURRENT_LOGIN_PERMISSION+ one.getId().toString();
        redisTemplate.opsForValue().set(key,permissionList, RConst.Num.INT_30, TimeUnit.MINUTES);
        return permissionList;
    }
}
